﻿using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;

using MTP.Core.Filters;

namespace MTP.Core
{
    class MtpCoreService : IHostedService
    {
        private readonly MtpOptions options;

        private readonly IMtpService dispatchServer;

        private readonly IServiceProvider serviceProvider;

        private readonly IMTPRegistry mtpRegistry;

        public MtpCoreService(IOptions<MtpOptions> options, IServiceProvider serviceProvider)
        {
            this.options = options.Value;
            this.serviceProvider = serviceProvider;
            this.mtpRegistry = this.options.Registry?.Invoke(serviceProvider);
            dispatchServer = MtpFactory
                .CreateService(this.options.Port, this.options.HostName, this.options.Cipher)
                .OnReceive(Receive);

        }


        public Stream Receive(Stream stream, string header)
        {
            using (IServiceScope scope = serviceProvider.CreateScope())
            {
                var headerDict = MTPCoreUtil.GetHeaderDict(header);

                var serviceContext = ServiceContext.CreateFromFactory(headerDict, options);
                return serviceContext.Execute(scope.ServiceProvider, stream, headerDict);
            }
        }

        public async Task StartAsync(CancellationToken cancellationToken)
        {
            if (mtpRegistry != null)
            {
                mtpRegistry.Reload += MtpRegistry_Reload;
                await mtpRegistry.Connect();

            }
            if (options.Services.Count == 0)
            {
                await mtpRegistry.Registry(0, null, null);
                return;
            }
            else
            {
                await mtpRegistry.Registry(options.Port, options.Cipher, options.Services.Select(a => a.Key).ToArray());
            }
            if (MtpRunFilters())
            {
                dispatchServer.Start();
                if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                {
                    Console.WriteLine("[40m[32minfo[39m[22m[49m: Microsoft.Hosting.Lifetime[0]");
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.Green;
                    Console.Write("info");
                    Console.ResetColor();
                    Console.WriteLine(": Microsoft.Hosting.Lifetime[0]");
                }

                Console.WriteLine($"      MTP.Core started: {options.MtpUrl}");

            }
        }

        private void MtpRegistry_Reload(RemoteOptions[] remoteOptions)
        {
            options.AddRemoteServices(remoteOptions);
        }


        /// <summary>
        /// 启动过滤
        /// </summary>
        /// <returns></returns>
        private bool MtpRunFilters()
        {
            try
            {
                if (options.Filters.Where(a => a is IMtpRunFilter)
                     .Any(a => !(a as IMtpRunFilter).OnMtpRunning(options, dispatchServer)))
                {
                    return false;
                }
                return true;
            }
            catch (Exception)
            {

            }
            return false;
        }


        public Task StopAsync(CancellationToken cancellationToken)
        {
            try
            {
                dispatchServer.Stop();

            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }

            return Task.CompletedTask;
        }


    }
}
